﻿using System;
using System.Collections.Generic;

namespace Flagwind.Data
{
	/// <summary>
	/// 内存缓存类。
	/// </summary>
	internal class MemoryCache<T>
	{
		#region 私有字段

		private readonly IDictionary<string, CacheValueItem<T>> _cache;
		private readonly object _syncLock = new object();
		private static object _instanceLock = new object();
		private DateTime _lastCheckTime;
		private static MemoryCache<T> _instance;

		#endregion

		#region 公共属性

		/// <summary>
		/// 获取当前类型的默认实例。
		/// </summary>
		public static MemoryCache<T> Default
		{
			get
			{
				if(_instance == null)
				{
					lock(_instanceLock)
					{
						if(_instance == null)
						{
							var buffer = new MemoryCache<T>();
							_instance = buffer;
						}
					}
				}
				return _instance;
			}
		}

		#endregion

		#region 构造方法

		/// <summary>
		/// 初始化 MemoryCache 类的新实例。
		/// </summary>
		private MemoryCache()
		{
			_cache = new Dictionary<string, CacheValueItem<T>>();
			_lastCheckTime = DateTime.Now;
		}

		#endregion

		#region 新增

		public void Add(string name, T value)
		{
			this.CheckCache();
			_cache.Add(name, new CacheValueItem<T>(value));
		}

		public void Add(CacheItem<T> item)
		{
			_cache.Add(item.Name, item);
		}

		#endregion

		#region 获取

		public T Get(string name)
		{
			var value = _cache[name];
			if(value != null)
			{
				return value.Value;
			}
			else
			{
				return default(T);
			}
		}

		public T Get<TParameter>(string name, Func<TParameter, T> initValue, TParameter parameter)
		{
			CacheValueItem<T> data;
			_cache.TryGetValue(name, out data);
			if(data != null)
			{
				return data.Value;
			}
			else
			{
				T value = initValue(parameter);
				this.Add(name, value);
				return value;
			}
		}

		#endregion

		#region 移除

		public bool Remove(string name)
		{
			return _cache.Remove(name);
		}

		#endregion

		#region 私有方法

		/// <summary>
		/// 清理缓存。
		/// </summary>
		private void Clear()
		{
			List<string> expireKey = new List<string>();
			var hotCache = _cache as NameValueDictionary<CacheValueItem<T>>;
			foreach(var item in hotCache)
			{
				if(item.Value != null)
				{
					if(item.Value.IsAbsoluteExpire && item.Value.ExpireTime < DateTime.Now)
					{
						expireKey.Add(item.Key);
					}
					else if(item.Value.HitCount < 0)
					{
						expireKey.Add(item.Key);
					}
					else
					{
						item.Value.SubHit();
					}
				}
			}
			foreach(string key in expireKey)
			{
				hotCache.Remove(key);
			}
		}

		/// <summary>
		/// 检查缓存是否符合情理条件，如果符合则出发清理操作。
		/// </summary>
		private void CheckCache()
		{
			if(DateTime.Now.Subtract(_lastCheckTime).TotalMinutes > 5)
			{
				lock(_syncLock)
				{
					if(DateTime.Now.Subtract(_lastCheckTime).TotalMinutes > 5)
					{
						this.Clear();
						_lastCheckTime = DateTime.Now;
					}
				}
			}
		}

		#endregion
	}
}